/*
 * Copyright (C) 2008 TranceCode Software
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 *
 * $Id$
 */
package org.trancecode.rdf.query;

import org.trancecode.rdf.Model;
import org.trancecode.rdf.Reference;
import org.trancecode.rdf.Triple;
import org.trancecode.rdf.UriReference;
import org.trancecode.rdf.Value;

import java.util.Collection;

import com.google.common.collect.ImmutableSet;


/**
 * Simple {@link Triple} query.
 * 
 * @author Herve Quiroz
 * @version $Revision: 3842 $
 */
public final class TripleQuery
{
	protected static final Collection<Reference> EMPTY_SUBJECTS = ImmutableSet.of();
	protected static final Collection<UriReference> EMPTY_PREDICATES = ImmutableSet.of();
	protected static final Collection<Value> EMPTY_OBJETS = ImmutableSet.of();
	protected static final Collection<UriReference> EMPTY_REFERENCES = ImmutableSet.of();

	public final Collection<Reference> subjects;
	public final Collection<UriReference> predicates;
	public final Collection<Value> objects;
	public final Collection<UriReference> references;


	public TripleQuery()
	{
		this(EMPTY_SUBJECTS, EMPTY_PREDICATES, EMPTY_OBJETS, EMPTY_REFERENCES);
	}


	private TripleQuery(
		final Collection<Reference> subjects, final Collection<UriReference> predicates,
		final Collection<Value> objects, final Collection<UriReference> references)
	{
		super();
		this.subjects = ImmutableSet.copyOf(subjects);
		this.predicates = ImmutableSet.copyOf(predicates);
		this.objects = ImmutableSet.copyOf(objects);
		this.references = ImmutableSet.copyOf(references);
	}


	public TripleQuery withObject(final Value... objects)
	{
		return withObject(ImmutableSet.of(objects));
	}


	public TripleQuery withObject(final Iterable<Value> objects)
	{
		return new TripleQuery(subjects, predicates, ImmutableSet.copyOf(objects), references);
	}


	public TripleQuery withPredicate(final UriReference... predicates)
	{
		return withPredicate(ImmutableSet.of(predicates));
	}


	public TripleQuery withPredicate(final Iterable<UriReference> predicates)
	{
		return new TripleQuery(subjects, ImmutableSet.copyOf(predicates), objects, references);
	}


	public TripleQuery withSubject(final Reference... subjects)
	{
		return withSubject(ImmutableSet.of(subjects));
	}


	public TripleQuery withSubject(final Iterable<Reference> subjects)
	{
		return new TripleQuery(ImmutableSet.copyOf(subjects), predicates, objects, references);
	}


	public TripleQuery withReference(final UriReference... uris)
	{
		return withReference(ImmutableSet.of(uris));
	}


	public TripleQuery withReference(final Iterable<UriReference> uris)
	{
		return new TripleQuery(subjects, predicates, objects, ImmutableSet.copyOf(uris));
	}


	public ExecutableTripleQuery compile(final Model model)
	{
		if (model instanceof TripleQueryCompiler)
		{
			return ((TripleQueryCompiler)model).compile(this);
		}

		return new GenericExecutableTripleQuery(model, this);
	}


	public Model execute(final Model model)
	{
		return compile(model).execute();
	}
}
